package com.zzb.projectfactory.framework.common;

import com.zzb.projectfactory.framework.query.*;
import com.zzb.projectfactory.framework.utils.DateUtil;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import javax.persistence.Column;
import javax.persistence.Table;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 基本分页查询dao 使用的是jdbcTemplate 只做显示用，不可以在业务操作时使用该方法，会导致事务问题
 * Created by zhangzhenbin on 2017/1/3.
 */
@Component
public class GenericQueryDAO {
    private static final Logger logger = LoggerFactory.getLogger(GenericQueryDAO.class);
    @Autowired
    JdbcTemplate jdbcTemplate;

    public <T> BasePage<T> queryPage(String querySql, Class<T> clazz, int page, int pageSize, Object... params) throws QueryException {
        try {
            String countSql = QuerySqlToCountSqlConvert.getCountSql(querySql);
            long total = jdbcTemplate.queryForObject(countSql, Long.class, params);
            List<T> list = jdbcTemplate.query(querySql, new AnnotationColumnRowMapper<T>(clazz), params);
            return new BasePage<T>(list, page, pageSize, total);
        } catch (DataAccessException e) {
            throw new QueryException("DataAccessException", e);
        }
    }

    public <S extends PageSearchForm, T> BasePage<T> queryPage(S searchForm, Class<T> clazz) {
        try {
            List<QueryMethodItem> methodItemList = QueryMethodBuilder.build(searchForm, clazz);
            String querySql = "select t.* ";
            String countSql = " select count(1) ";
            Table table = clazz.getAnnotation(Table.class);
            StringBuilder sqlCondition =
                    new StringBuilder(" from " + table.name() + " t where 1= 1 ");
            String orderBy = null;
            Field[] allDeclaredFields = ReflectionUtils.getAllDeclaredFields(clazz);
            for (Field field : allDeclaredFields) {
                Column columnAnnotation = field.getAnnotation(Column.class);
                if (columnAnnotation == null) continue;
                String columnName = columnAnnotation.name();
                if (field.getName().equals("id")) {
                    orderBy = "id";
                }
                if (field.getType() == Date.class) {
                    if (orderBy == null || orderBy.equals("id") || field.getName().contains("create")) {
                        orderBy = columnName;
                    }
                }
            }
            if (orderBy != null) {
                orderBy = orderBy + " desc";
            }
            List<Object> params = new ArrayList<>();
            for (QueryMethodItem item : methodItemList) {
                //包含空值就取消
                if (item.getMethod() == null ||
                        StringUtils.isBlank(item.getColumnName()) ||
                        item.getType() == null ||
                        item.getValue() == null) continue;

                sqlCondition
                        .append("and ")
                        .append("t.")
                        .append(item.getColumnName())
                        .append(" ")
                        .append(item.getMethod().getValue())
                        .append(" ? ");
                Object value = item.getValue();
                if (item.getMethod().equals(QueryMethodEnum.contain)) {
                    value = "%" + value + "%";
                }
//                if (value instanceof Date) {
//                    value = "'" + new DateTime(value).toString("yyyy-MM-dd HH:mm:ss") + "'";
//                }
                if (item.getType().equals(Date.class) && value instanceof String) {
                    value = DateUtil.stringForceToDate((String) value);
                }
                params.add(value);
            }
            //排序
            if (StringUtils.isNotBlank(searchForm.getOrderBy())) {
                orderBy = searchForm.getOrderBy();
            }
            StringBuilder orderStringBuilder = new StringBuilder();
            if (orderBy != null) {
                String columnName;
                int descIndex;
                if ((descIndex = orderBy.indexOf("desc")) == -1) {
                    descIndex = orderBy.indexOf("asc");
                }
                String[] split = orderBy.substring(0, descIndex).split(" ");
                if (ArrayUtils.isNotEmpty(split)) {
                    String name = split[split.length - 1];
                    try {
                        Field declaredField = ReflectionUtils.getAllDeclaredField(clazz, name);
                        Column columnAnnotation = declaredField.getAnnotation(Column.class);
                        columnName = columnAnnotation.name();

                    } catch (Exception e) {
                        columnName = name;
                    }
                    orderBy = orderBy.replace(name,columnName);
                }
                if (!orderBy.contains("order by"))
                    orderStringBuilder.append(" order by ").append(orderBy);
            }

            //分页
            StringBuilder limitStringBuilder = new StringBuilder();
            if (searchForm.getPage() != null && searchForm.getPageSize() != null) {
                int offset = (searchForm.getPage() - 1) * searchForm.getPageSize();
                limitStringBuilder.append(" limit ").append(offset).append(" , ").append(searchForm.getPageSize());
            }

            querySql = querySql + sqlCondition.toString() + orderStringBuilder.toString() + limitStringBuilder.toString();
            countSql += sqlCondition;
            List<T> list = jdbcTemplate.query(querySql, new AnnotationColumnRowMapper<T>(clazz), params.toArray());
            Long count = jdbcTemplate.queryForObject(countSql, Long.class, params.toArray());
            logger.debug(querySql);
            return new BasePage<>(list, searchForm.getPage(), searchForm.getPageSize(), count);
        } catch (IllegalAccessException | NoSuchFieldException e) {
            e.printStackTrace();
            return null;
        }
    }
}
